# -*- coding: utf-8 -*-
"""
装饰器工具模块
提供各种通用的装饰器函数
"""

import time
import functools
import logging
from typing import Any, Callable, Optional, Union
from requests import Response

from .logger import get_logger


def retry_on_failure(
    max_retries: int = 3,
    delay: float = 1.0,
    backoff: float = 2.0,
    exceptions: tuple = (Exception,),
    logger: Optional[logging.Logger] = None
):
    """
    失败重试装饰器
    
    Args:
        max_retries: 最大重试次数
        delay: 初始延迟时间（秒）
        backoff: 延迟时间倍数
        exceptions: 需要重试的异常类型
        logger: 日志器
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            _logger = logger or get_logger(func.__module__)
            last_exception = None
            current_delay = delay
            
            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e
                    if attempt < max_retries:
                        _logger.warning(
                            f"函数 {func.__name__} 第 {attempt + 1} 次执行失败: {str(e)}, "
                            f"{current_delay:.1f}秒后重试"
                        )
                        time.sleep(current_delay)
                        current_delay *= backoff
                    else:
                        _logger.error(
                            f"函数 {func.__name__} 重试 {max_retries} 次后仍然失败: {str(e)}"
                        )
                        raise last_exception
            
            return None
        return wrapper
    return decorator


def log_execution_time(
    logger: Optional[logging.Logger] = None,
    level: int = logging.INFO,
    message_template: str = "函数 {func_name} 执行时间: {execution_time:.3f}秒"
):
    """
    记录函数执行时间的装饰器
    
    Args:
        logger: 日志器
        level: 日志级别
        message_template: 日志消息模板
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            _logger = logger or get_logger(func.__module__)
            
            start_time = time.time()
            try:
                result = func(*args, **kwargs)
                return result
            finally:
                end_time = time.time()
                execution_time = end_time - start_time
                _logger.log(
                    level,
                    message_template.format(
                        func_name=func.__name__,
                        execution_time=execution_time
                    )
                )
        return wrapper
    return decorator


def validate_response(
    expected_status_codes: Union[int, list] = None,
    required_keys: list = None,
    logger: Optional[logging.Logger] = None
):
    """
    验证API响应的装饰器
    
    Args:
        expected_status_codes: 期望的状态码
        required_keys: 响应JSON中必须包含的键
        logger: 日志器
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            _logger = logger or get_logger(func.__module__)
            
            # 执行原函数
            result = func(*args, **kwargs)
            
            # 如果返回值是Response对象，进行验证
            if isinstance(result, Response):
                # 验证状态码
                if expected_status_codes is not None:
                    if isinstance(expected_status_codes, int):
                        expected_codes = [expected_status_codes]
                    else:
                        expected_codes = expected_status_codes
                    
                    if result.status_code not in expected_codes:
                        error_msg = (
                            f"状态码验证失败: 期望 {expected_codes}, "
                            f"实际 {result.status_code}"
                        )
                        _logger.error(error_msg)
                        raise AssertionError(error_msg)
                
                # 验证响应键
                if required_keys:
                    try:
                        response_json = result.json()
                        missing_keys = []
                        
                        for key in required_keys:
                            if key not in response_json:
                                missing_keys.append(key)
                        
                        if missing_keys:
                            error_msg = f"响应中缺少必需的键: {missing_keys}"
                            _logger.error(error_msg)
                            raise AssertionError(error_msg)
                    
                    except ValueError:
                        error_msg = "响应不是有效的JSON格式"
                        _logger.error(error_msg)
                        raise AssertionError(error_msg)
            
            return result
        return wrapper
    return decorator


def timeout(seconds: float):
    """
    函数超时装饰器
    
    Args:
        seconds: 超时时间（秒）
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            import signal
            
            def timeout_handler(signum, frame):
                raise TimeoutError(f"函数 {func.__name__} 执行超时 ({seconds}秒)")
            
            # 设置超时信号
            old_handler = signal.signal(signal.SIGALRM, timeout_handler)
            signal.alarm(int(seconds))
            
            try:
                result = func(*args, **kwargs)
                return result
            finally:
                # 恢复原来的信号处理器
                signal.alarm(0)
                signal.signal(signal.SIGALRM, old_handler)
        
        return wrapper
    return decorator


def cache_result(ttl: float = 300):
    """
    缓存函数结果的装饰器
    
    Args:
        ttl: 缓存生存时间（秒）
    """
    def decorator(func: Callable) -> Callable:
        cache = {}
        
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = str(args) + str(sorted(kwargs.items()))
            current_time = time.time()
            
            # 检查缓存
            if cache_key in cache:
                result, timestamp = cache[cache_key]
                if current_time - timestamp < ttl:
                    return result
                else:
                    # 缓存过期，删除
                    del cache[cache_key]
            
            # 执行函数并缓存结果
            result = func(*args, **kwargs)
            cache[cache_key] = (result, current_time)
            
            return result
        
        # 添加清除缓存的方法
        wrapper.clear_cache = lambda: cache.clear()
        wrapper.cache_info = lambda: {
            'cache_size': len(cache),
            'ttl': ttl
        }
        
        return wrapper
    return decorator


def rate_limit(calls_per_second: float = 1.0):
    """
    限制函数调用频率的装饰器
    
    Args:
        calls_per_second: 每秒允许的调用次数
    """
    def decorator(func: Callable) -> Callable:
        min_interval = 1.0 / calls_per_second
        last_called = [0.0]
        
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            current_time = time.time()
            elapsed = current_time - last_called[0]
            
            if elapsed < min_interval:
                sleep_time = min_interval - elapsed
                time.sleep(sleep_time)
            
            last_called[0] = time.time()
            return func(*args, **kwargs)
        
        return wrapper
    return decorator


def deprecated(reason: str = "", version: str = ""):
    """
    标记函数为已弃用的装饰器
    
    Args:
        reason: 弃用原因
        version: 弃用版本
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            import warnings
            
            message = f"函数 {func.__name__} 已弃用"
            if version:
                message += f" (自版本 {version})"
            if reason:
                message += f": {reason}"
            
            warnings.warn(message, DeprecationWarning, stacklevel=2)
            return func(*args, **kwargs)
        
        return wrapper
    return decorator


def exception_handler(
    exceptions: tuple = (Exception,),
    default_return: Any = None,
    logger: Optional[logging.Logger] = None,
    reraise: bool = False
):
    """
    异常处理装饰器
    
    Args:
        exceptions: 要捕获的异常类型
        default_return: 异常时的默认返回值
        logger: 日志器
        reraise: 是否重新抛出异常
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            _logger = logger or get_logger(func.__module__)
            
            try:
                return func(*args, **kwargs)
            except exceptions as e:
                _logger.error(
                    f"函数 {func.__name__} 执行时发生异常: {str(e)}",
                    exc_info=True
                )
                
                if reraise:
                    raise
                
                return default_return
        
        return wrapper
    return decorator